#include <string>
#include <sstream>
#include <stdio.h>
#include "port.h"
#include "gui.h"
#include "view.h"
#include "background.h"
#include "game.h"

#define STRING_LENGTH 128

// Text
// This is because of compiler errors
char *mainMenu_text[] =
{ "New Game",
    "Options",
    "Exit"
};

char *options_text[] =
{ NULL,
    "Blur particles on collision",
    "Mark particles when few left",
    "Optimize physics zones",
    NULL,
    "Physics resolution",
    "Back"
};

// Additional dialog functions and variables
BITMAP *preview;
BITMAP *back;
Background *bg;
Config *cfg;

int closeDialog(void) { return D_CLOSE; }

// TODO: Preferably not duplicate these
int num_to_text_planets(void *dp3, int d2)
{
    char *str = (char *)dp3;
    memset(str,0,STRING_LENGTH);
    snprintf(str,STRING_LENGTH, "%d planets", d2);

    cfg->numPlanets = d2;
    bg->generateMap();
    clear_to_color(preview, 0);
    masked_stretch_blit(back, preview, 0, 0, back->w, back->h, 0, 0,
            preview->w,preview->h);

    return D_REDRAW;
}

int num_to_text_physres(void *dp3, int d2)
{
    char *str = (char *)dp3;
    memset(str,0,STRING_LENGTH);
    snprintf(str,STRING_LENGTH, "%d physics resolution", d2);

    return D_REDRAW;
}




// Most items in this file are set-up by a function
DIALOG mainMenu[] =
{ //     proc,		x, y, w, h, fg, bg, key, flags, d1, d2, dp, dp2, dp3
    { d_button_proc,0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
#define NEW_GAME 0
    { d_button_proc,0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
#define OPTIONS 1
    { d_button_proc,0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
#define EXIT 2
    { NULL,		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
};


char opt_physics_res[STRING_LENGTH] = "24 physics resolution";
DIALOG options[] =
{ //     proc,		x, y, w, h, fg, bg, key, flags, d1, d2, dp, dp2, dp3
    { d_box_proc,0, 0, 0, 0, 0, 0, 0, 0, 1, 0, NULL, NULL, NULL },
#define OPTIONS_BOX 0

#define CHECKBOX_BEGIN 1
    { d_check_proc,0, 0, 0, 0, 0, 0, 0, 0, 1, 0, NULL, NULL, NULL },
#define OPT_BLUR_PARTICLES 1	
    { d_check_proc,0, 0, 0, 0, 0, 0, 0, 0, 1, 0, NULL, NULL, NULL },
#define OPT_WHITE_PARTICLES 2
    { d_check_proc,0, 0, 0, 0, 0, 0, 0, 0, 1, 0, NULL, NULL, NULL },
#define OPT_OPTIMIZE_PHYSICS 3
    { d_slider_proc, 0,0,0,0, 0,0, 0, 0, 64, 24, NULL,
        (void*)num_to_text_physres, opt_physics_res},
#define OPT_PHYSRES_SLIDER 4

#define CHECKBOX_END 4


    { d_text_proc, 0,0,0,0, 0,0, 0, 0, 0,0, opt_physics_res,NULL,NULL},
#define SLIDER_TEXT 5
    { d_button_proc,0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
#define OPTIONS_BACK 6
    { NULL,		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
};

// New game dialog and associated data
char ng_num_planets[STRING_LENGTH] = "8 planets";
char *mapSettings = "Map settings:";
char *startGame = "Start";
DIALOG newGame[] =
{ //     proc,		x, y, w, h, fg, bg, key, flags, d1, d2, dp, dp2, dp3
    { d_box_proc,0, 0, 0, 0, 0, 0, 0, 0, 1, 0, NULL, NULL, NULL },
#define NEWG_BOX 0
    { d_text_proc,0, 0, 0, 0, 0, 0, 0, 0, 1, 0, mapSettings, NULL, NULL },
#define NEWG_MAP_TEXT 1
    { d_slider_proc,0, 0, 0, 0, 0, 0, 0, 0, 32, 8, NULL,
        (void*)num_to_text_planets, ng_num_planets },
#define NEWG_NUM_PLANETS_SLIDER 2
    { d_text_proc,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ng_num_planets, NULL, NULL},
#define NEWG_NUM_PLANETS_TEXT 3

    //{ d_text_proc, 0,0,0,0, 0,0, 0, 0, 64, 24, NULL, NULL, NULL},
#define NEWG_GAME_TEXT 4

    //{ d_button_proc,0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
#define NEWG_MONEY_TEXT 5
    //{ d_button_proc,0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
#define NEWG_MONEY_EDIT 6

    { d_button_proc,0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, startGame, NULL,
        NULL },
#define NEWG_START 4
    { d_keyboard_proc,0, 0, 0, 0, 0, 0, 0, D_EXIT, KEY_ENTER, 0,
        (void*)closeDialog, NULL, NULL },
    //#define NEWG_KEYBOARD 5
    { d_bitmap_proc,0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
#define NEWG_PREVIEW 6
    { NULL,		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
};

void Gui::setup(void)
{
    // Shared
    set_dialog_color(mainMenu, makecol(64,64,64), makecol(255,255,192));
    set_dialog_color(options, makecol(64,64,64), makecol(255,255,192));
    set_dialog_color(newGame, makecol(64,64,64), makecol(255,255,192));


    // Main menu
#define MM_BUTTON_W 100
#define MM_BUTTON_H 40
    {
        // New game button
        mainMenu[NEW_GAME].dp = mainMenu_text[NEW_GAME];
        mainMenu[NEW_GAME].x = SCREEN_W/2-MM_BUTTON_W/2;
        mainMenu[NEW_GAME].y = SCREEN_H/2-MM_BUTTON_H*2;
        mainMenu[NEW_GAME].w = MM_BUTTON_W;
        mainMenu[NEW_GAME].h = MM_BUTTON_H;

        // Options button
        mainMenu[OPTIONS].dp = mainMenu_text[OPTIONS];
        mainMenu[OPTIONS].x = SCREEN_W/2-MM_BUTTON_W/2;
        mainMenu[OPTIONS].y = SCREEN_H/2-MM_BUTTON_H/2;
        mainMenu[OPTIONS].w = MM_BUTTON_W;
        mainMenu[OPTIONS].h = MM_BUTTON_H;

        // Exit button
        mainMenu[EXIT].dp = mainMenu_text[EXIT];
        mainMenu[EXIT].x = SCREEN_W/2-MM_BUTTON_W/2;
        mainMenu[EXIT].y = SCREEN_H/2+MM_BUTTON_H*1;
        mainMenu[EXIT].w = MM_BUTTON_W;
        mainMenu[EXIT].h = MM_BUTTON_H;
    }

    // Options menu
#define OPT_BOX_W 600
#define OPT_BOX_H 400
#define BUTTON_W 70
#define BUTTON_H 30
    {
        int boxX,boxY;
        boxX = SCREEN_W/2-OPT_BOX_W/2;
        boxY = SCREEN_H/2-OPT_BOX_H/2;

        options[OPTIONS_BOX].x = boxX;
        options[OPTIONS_BOX].y = boxY;
        options[OPTIONS_BOX].w = OPT_BOX_W;
        options[OPTIONS_BOX].h = OPT_BOX_H;

        for(int i=CHECKBOX_BEGIN;i<=CHECKBOX_END;i++) {
            options[i].dp = options_text[i];
            options[i].x = boxX+5;
            options[i].y = boxY+5+15*(i-CHECKBOX_BEGIN+1);
            options[i].w = 15*20;
            options[i].h = 15;
        }

        options[OPT_PHYSRES_SLIDER].w = 64*2;

        options[SLIDER_TEXT].x = options[OPT_PHYSRES_SLIDER].x + 64*2+2;
        options[SLIDER_TEXT].y = options[OPT_PHYSRES_SLIDER].y;
        options[SLIDER_TEXT].w = options[OPT_PHYSRES_SLIDER].w;
        options[SLIDER_TEXT].h = options[OPT_PHYSRES_SLIDER].h;

        options[OPTIONS_BACK].dp = options_text[OPTIONS_BACK];
        options[OPTIONS_BACK].x = boxX+5;
        options[OPTIONS_BACK].y = boxY+OPT_BOX_H - BUTTON_H - 5;
        options[OPTIONS_BACK].w = BUTTON_W;
        options[OPTIONS_BACK].h = BUTTON_H;;
    }

    // New game menu
    {
        newGame[NEWG_BOX].x = 0;
        newGame[NEWG_BOX].y = 0;
        newGame[NEWG_BOX].w = OPT_BOX_W;
        newGame[NEWG_BOX].h = OPT_BOX_H;

        newGame[NEWG_MAP_TEXT].x = OPT_BOX_W/2;
        newGame[NEWG_MAP_TEXT].y = 15;
        newGame[NEWG_MAP_TEXT].w = 92;
        newGame[NEWG_MAP_TEXT].h = 15;

        newGame[NEWG_NUM_PLANETS_SLIDER].x = OPT_BOX_W/2;
        newGame[NEWG_NUM_PLANETS_SLIDER].y = 10 + 20;
        newGame[NEWG_NUM_PLANETS_SLIDER].w = 92;
        newGame[NEWG_NUM_PLANETS_SLIDER].h = 15;

        newGame[NEWG_NUM_PLANETS_TEXT].x = OPT_BOX_W/2 + 92 +5;
        newGame[NEWG_NUM_PLANETS_TEXT].y = 12 + 20;
        newGame[NEWG_NUM_PLANETS_TEXT].w = 64*2;
        newGame[NEWG_NUM_PLANETS_TEXT].h = 15;
        newGame[NEWG_NUM_PLANETS_TEXT].dp = ng_num_planets;

        newGame[NEWG_START].x = 5;
        newGame[NEWG_START].y = OPT_BOX_H - BUTTON_H - 5;
        newGame[NEWG_START].w = BUTTON_W;
        newGame[NEWG_START].h = BUTTON_H;

#define PREVIEW_W 260
#define PREVIEW_H 166
        newGame[NEWG_PREVIEW].x = OPT_BOX_W - PREVIEW_W - 30;
        newGame[NEWG_PREVIEW].y = OPT_BOX_H - PREVIEW_H - 30;
        newGame[NEWG_PREVIEW].w = PREVIEW_W;
        newGame[NEWG_PREVIEW].h = PREVIEW_H;
        preview = create_bitmap(PREVIEW_W,PREVIEW_H);
        clear_bitmap(preview);
        newGame[NEWG_PREVIEW].dp = preview;

        // Recenter dialog
        centre_dialog(newGame);
    }
}

void Gui::MainMenu(GameModule *g)
{
    DIALOG_PLAYER *dlg;
    BITMAP *buf;
    int ret;

    ret = NEW_GAME;
    buf = g->getView()->getBuffer();
    gui_set_screen(buf);
    while (ret != EXIT || key[KEY_ESC]) {
        dlg = init_dialog(mainMenu, -1);

        // Do actual dialog
        g->newGame(GAME_DEMO);
        // Included check for KEY_ESC because we don't want to shut down
        // due to that
        while (update_dialog(dlg) || key[KEY_ESC]) {
            g->run();

            // Draw dialog object every frame
            if (g->frameUpdate) // To save some processing power
                g->getView()->paint(g);

            broadcast_dialog_message(MSG_DRAW, 0);
            draw_sprite(buf, mouse_sprite, mouse_x,mouse_y);
            blit(buf,screen, 0,0,0,0, buf->w,buf->h);
            clear_bitmap(buf);
        }
        g->getData()->clear();

        ret = shutdown_dialog(dlg);

        switch(ret)
        {
            case NEW_GAME:
                if (Gui::NewGameMenu(g)) {
                    g->newGame(GAME_NORMAL);
                    g->run();
                }
                clear_keybuf();
                gui_set_screen(buf);
                break;

            case OPTIONS:
                Gui::OptionsMenu(g);
                gui_set_screen(buf);
                // Disabled for now
                break;
        }
    }
}

bool Gui::NewGameMenu(GameModule *g)
{
    int ret;
    cfg = g->getData()->getconfig();

    // Set background bitmap
    bg = g->getData()->getBackground();
    bg->generateMap();
    back = bg->getBackground();
    clear_to_color(preview, 0);
    masked_stretch_blit(back, preview, 0, 0, back->w, back->h, 0, 0,
            preview->w,preview->h);

    gui_set_screen(NULL);
    ret = do_dialog(newGame,-1);

    // Set settings based on dialog
    //cfg->numPlanets = newGame[NEWG_NUM_PLANETS_SLIDER].d2;

    return true;
}

void Gui::OptionsMenu(GameModule *g)
{
    g->getData()->loadconfig();
    Config *cfg = g->getData()->getconfig();

    // Set gui stuff based on config data
    options[OPT_PHYSRES_SLIDER].d2 = cfg->physPartitionRes;
    options[OPT_BLUR_PARTICLES].flags = (cfg->blurParticles==1
            ? D_SELECTED : 0);
    options[OPT_WHITE_PARTICLES].flags = (cfg->whiteParticles==1
            ? D_SELECTED : 0);
    options[OPT_OPTIMIZE_PHYSICS].flags = (cfg->optimizePhysics==1
            ? D_SELECTED : 0);

    // Update GUI strings
    num_to_text_physres(options[OPT_PHYSRES_SLIDER].dp3,
            options[OPT_PHYSRES_SLIDER].d2);

    // Run GUI
    gui_set_screen(NULL);
    popup_dialog(options, -1);

    // Set flags based on gui response
    if (options[OPT_BLUR_PARTICLES].flags & D_SELECTED) {
        cfg->blurParticles = true;
    } else cfg->blurParticles = false;

    if (options[OPT_WHITE_PARTICLES].flags & D_SELECTED) {
        cfg->whiteParticles = true;
    } else cfg->whiteParticles = false;

    if (options[OPT_OPTIMIZE_PHYSICS].flags & D_SELECTED) {
        cfg->optimizePhysics = true;
    } else cfg->optimizePhysics = false;

    cfg->physPartitionRes = options[OPT_PHYSRES_SLIDER].d2;

    g->getData()->saveconfig();
}
